package uk.co.wroedevelopments.semanticworkbench.query;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.neo4j.api.core.Transaction;
import org.xtext.example.semQryDsl.Node;
import org.xtext.example.semQryDsl.Param;
import org.xtext.example.semQryDsl.Pattern;
import org.xtext.example.semQryDsl.Query;
import org.xtext.example.semQryDsl.SemQryDslPackage;
import org.xtext.example.semQryDsl.util.SemQryDslSwitch;

import uk.co.wroedevelopments.semanticworkbench.store.Connection;

public class QueryPlan {

	private List<QueryAction> planSteps;

	/*
	 * take the patterns and work out where to start Look through all patterns
	 * to find ones with concrete node Find the triples meeting those patterns.
	 * Then work out for >2 params what the solution is for that pattern
	 * 
	 * if a relationship type is transitive then walk across that
	 * 
	 * End goal is a set of triples which meet the pattern, then bind the
	 * variables and output the results.
	 * 
	 * Could look at the SPARQL implementation?
	 */

	public QueryPlan() {
		super();
		planSteps = new ArrayList<QueryAction>();

	}

	public void generatePlan(Query qry) {
		List<Pattern> pats = findConcretePatterns(qry);
		generateConcreteQuerySteps(pats);
		System.out.println(pats.size());
	}

	public void executePlan(Query qry) {
		List<ResultList> overallResult = new ArrayList<ResultList>();
		Transaction tx = Connection.getService().beginTx();
		try {
			for (QueryAction a : planSteps) {
				ResultList res = a.perform();
				overallResult.add(res);

			}

			// do some set manipulation to find intersections
			// do some binding to variables.
			// and return
			System.out.println("got here");
			EList<Param> params = getOutputParams(qry);
			for (Param param : params) {
				param.getName();
				for (ResultList rl : overallResult) {
					List<org.neo4j.api.core.Node> nodes = rl
							.getBindingNodes(param.getName());
					for (org.neo4j.api.core.Node nde : nodes) {
						System.out.println(nde
								.getProperty(QueryUtils.NODE_ID_FIELD));
					}
				}
			}
			tx.success();
		} finally {
			tx.finish();
		}
	}

	private EList<Param> getOutputParams(Query qry) {
		return qry.getSelect().getParams();
	}

	private void generateConcreteQuerySteps(List<Pattern> pats) {
		// run a query for each pattern to bind some results sets to it
		for (Pattern p : pats) {
			NeoQueryAction step = new NeoQueryAction(p);
			planSteps.add(step);

		}
	}

	private List<Pattern> findConcretePatterns(Query qry) {

		List<Pattern> concretePatterns = new ArrayList<Pattern>();

		for (Pattern p : qry.getWhere().getPatterns()) {
			if (QueryUtils.hasConcreteInstance(p)) {
				concretePatterns.add(p);

			}
		}
		return concretePatterns;

	}

}
